package com.liangtian.mdm.base.aspect;

import com.alibaba.fastjson.JSON;
import com.liangtian.mdm.base.constants.ResultCode;
import com.liangtian.mdm.base.exception.BaseRuntimeException;
import com.liangtian.mdm.base.response.BaseResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author Qi
 */
@Aspect
@Component
@Order(1)
@Slf4j
public class LogAspect {
    @Pointcut("execution(public * com.liangtian.mdm.*.controller.*.*(..))")
    public void log() {
        //log.info("log()");
    }

    @Around(value = "log()")
    public Object around(ProceedingJoinPoint pjp) {
        try {
            //Step 1
            Object o = pjp.proceed();
            //Step 3
            if (o instanceof BaseResponse) {
                BaseResponse rlt = (BaseResponse) o;
                if (rlt.getMessage() == null) {
                    rlt.setMessage(ResultCode.fromCode(rlt.getCode()).getMsg());
                }
            } else {
                o = BaseResponse.genResponse(ResultCode.FAIL);
            }
            return o;
        } catch (Throwable e) {
            BaseResponse rlt = null;
            if (e instanceof BaseRuntimeException) {
                BaseRuntimeException ee = (BaseRuntimeException) e;
                if (ee.getMessage() == null) {
                    if (ResultCode.fromCode(ee.getCode())==null){
                        rlt = BaseResponse.genResponse(ResultCode.FAIL);
                    }else {
                        rlt = BaseResponse.genResponse(ee.getCode(), ResultCode.fromCode(ee.getCode()).getMsg(), null);
                    }
                } else {
                    rlt = BaseResponse.genResponse(ee.getCode(), ee.getMessage(), null);
                }
            } else {
                rlt = BaseResponse.genResponse(ResultCode.FAIL.getCode(), ResultCode.FAIL.getMsg(), null);
                log.error("运行异常", e);
            }

            return rlt;
        }
    }

    @Before(value = "log()")
    public void before(JoinPoint joinPoint) {
        //Step 2
        long reqTime = System.currentTimeMillis();
        String reqId = UUID.randomUUID().toString().replaceAll("-", "");
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        response.setCharacterEncoding("UTF-8");
        request.getSession().setAttribute("reqId", reqId);
        request.getSession().setAttribute("reqTime", reqTime);
        String url = request.getServletPath();
        String method = request.getMethod();
        String jsonStr = null;
        try {
            // jsonStr = JSON.toJSONString(joinPoint.getArgs());
            Object[] args = joinPoint.getArgs();
            Stream<?> stream = ArrayUtils.isEmpty(args) ? Stream.empty() : Arrays.stream(args);
            List<Object> logArgs = stream
                    .filter(arg -> (!(arg instanceof HttpServletRequest) && !(arg instanceof HttpServletResponse)))
                    .collect(Collectors.toList());
            //过滤后序列化无异常
            jsonStr = JSON.toJSONString(logArgs);
        } catch (Exception e) {
            // e.printStackTrace();
            jsonStr = "";
        }
        log.info("[{}]url:{},method:{},reqId:{},reqTime:{},data:{}", "sys_in", url, method, reqId, reqTime, jsonStr);
    }


    @AfterReturning(returning = "ret", pointcut = "log()")
    public void doAfterReturning(Object ret) {
        //Step 5
        if (log.isInfoEnabled()) {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String url = request.getServletPath();
            String method = request.getMethod();

            String reqId = (String) request.getSession().getAttribute("reqId");
            long costTime = System.currentTimeMillis() - (long) request.getSession().getAttribute("reqTime");
            String jsonStr = JSON.toJSONString(ret);
            log.info("[{}]url:{},method:{},reqId:{},costTime:{}ms,data:{}", "sys_out", url, method, reqId, costTime, jsonStr);
        }
    }

}


